import random

from django.contrib.auth import authenticate, login
from django_redis import get_redis_connection
from django.shortcuts import render, redirect

from areas.models import Area
from carts.utils import merge_cart
from goods.models import SKU
from users import constants
from meiduo_mall.utils.email import decipher_token
from .models import User, Address

# Create your views here.
from django.views import View
import json
import re

from django.contrib.auth import logout
from django.http import HttpResponseForbidden
from django.http import JsonResponse
from meiduo_mall.utils.email import generate_verify_url
from meiduo_mall.utils.response_code import RET
from celery_tasks.send_email.email_sender import email_sender
from django.contrib.auth.mixins import LoginRequiredMixin


class MyLoginRequiredMiXinView(LoginRequiredMixin, View):
    login_url = "/login/"


class RegisterView(View):
    def get(self, request):
        return render(request, 'register.html')

    def post(self, request):

        # 1. 获取参数
        user_name = request.POST.get('user_name')
        pwd = request.POST.get('pwd')
        cpwd = request.POST.get('cpwd')
        phone = request.POST.get('phone')
        allow = request.POST.get('allow')
        msg_code = request.POST.get('msg_code')

        # 2. 校验参数
        # 2.1 判断是否为空
        if not all([user_name, pwd, cpwd, phone]):
            return HttpResponseForbidden("对不起，输入的参数不全...")

        # 2.2 判断两次输入是的密码是否一致
        if not pwd == cpwd:
            return HttpResponseForbidden("对不起，两次输入的密码不一致...")

        # 2.3 正则判断手机号
        if not re.match(r'1[3-9]\d{9}', phone):
            return HttpResponseForbidden("对不起，输入手机格式不正确...")

        # 2.4 短信校验

        redis_conn = get_redis_connection("code")
        redis_sms_code = redis_conn.get("sms_code_%s" % phone)

        # 判断验证码是否过期
        if not redis_sms_code:
            return HttpResponseForbidden("手机验证码已经过期...")

        if not redis_sms_code.decode() == msg_code:
            return HttpResponseForbidden("手机验证码输入错误...")

        # 2.5  协议校验
        if not allow == "on":
            return HttpResponseForbidden("请同意协议...")

        # 3. 把参数写入数据库
        user = User.objects.create_user(username=user_name, password=pwd, mobile=phone)

        # 4. 返回值，响应
        return redirect("https://baidu.com")


class CheckUsernameView(View):
    # 查询是否存在
    def get(self, request, username):
        count = User.objects.filter(username=username).count()
        # 定义json数据
        data = {
            "count": count
        }
        return JsonResponse(data)


class CheckMobileView(View):

    def get(self, request, mobile):

        count = User.objects.filter(mobile=mobile).count()

        data = {

            "count": count
        }
        return JsonResponse(data)


class LoginUserView(View):

    def get(self, request):
        return render(request, "login.html")

    def post(self, request):
        # 获取参数
        username = request.POST.get("username")
        pwd = request.POST.get("pwd")
        remembered = request.POST.get("remembered")

        # 校验参数
        #   参数完整性校验
        if not all([username, pwd]):
            return HttpResponseForbidden("信息填写不完整...")

        #   用户的格式校验
        if not re.match(r'^[a-zA-Z0-9_-]{5,20}$', username):
            return HttpResponseForbidden("用户名格式填写有误...")

        #   密码的格式校验
        if not re.match(r'^[0-9A-Za-z]{8,20}$', pwd):
            return HttpResponseForbidden("密码格式填写有误...")

        #   密码的正确性校验

        # 方法一
        # user = User.objects.get(username=username)
        # if not user.check_password(pwd):
        #     return HttpResponseForbidden("用户密码错误...")

        # 方法二，用authenticate方法,校验成功返回一个model对象,不成功返回none
        user = authenticate(request, username=username, password=pwd)
        if not user:
            return HttpResponseForbidden("用户密码错误...")

        # 状态保持
        login(request, user)
        if remembered == "on":
            request.session.set_expiry(constants.SESSION_MAX_PERIOD)

        else:
            request.session.set_expiry(0)

        # 把用户名传入cookie, 方便在首页中js获取显示到网页第一行
        response = redirect("/")

        response.set_cookie("username", user.username)

        # 合并cookies和redis数据库中的购物车
        merge_cart(request, user, response)

        # 返回响应
        return response


class EmailActiveView(View):
    def get(self, request):
        s_token = request.GET.get("token")

        if not s_token:
            return HttpResponseForbidden("s_token已经丢失...")

        user = decipher_token(s_token)

        # 判断user是否为空
        if user:
            user.email_active = True
            user.save()

        return redirect("/info/")


class LogoutUserView(View):

    def get(self, request):

        # 删除session
        logout(request)

        # 删除cookies1
        response = redirect("/")

        response.delete_cookie("username")

        return response


# 继承LoginRequiredMixin类实现登陆验证
class UserCenterView(MyLoginRequiredMiXinView):
    # 第一种验证登陆状态的方法
    # def get(self, request):
    #
    #     if request.user.is_authenticated:
    #         return render(request, "user_center_info.html")
    #
    #     else:
    #         response = redirect("/login/")
    #         response.delete_cookie("username")
    #         return response

    def get(self, request):

        context = {
            "username": request.user.username,
            "mobile": request.user.mobile,
            "email": request.user.email,
            "email_active": request.user.email_active
        }

        return render(request, "user_center_info.html", context)


class EmailSendView(MyLoginRequiredMiXinView):
    def put(self, request):

        # 获取email

        req_dict = json.loads(request.body.decode())

        email = req_dict.get("email")

        # 为空校验
        if not email:
            return HttpResponseForbidden("邮箱为空...")

        # 格式校验
        if not re.match("^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$", email):
            return HttpResponseForbidden("邮箱格式错误...")

        verify_url = generate_verify_url(request.user)

        # 验证都通过后通过celery发送邮件
        email_sender.delay(verify_url, email)

        # 把email写入数据库中
        request.user.email = email
        request.user.save()

        # 返回email发送结果到前端
        data = {"code":RET.OK,"errmsg":"ok"}

        return JsonResponse(data)


class AddressView(View):

    def get(self, request):

        addresses = request.user.addresses.filter(is_deleted=False)

        address_list = list()

        for address in addresses:
            address_dict = {
                "id":address.id,
                "title":address.title,
                "receiver":address.receiver,
                "province":address.province.name,
                "city":address.city.name,
                "district":address.district.name,
                "place":address.place,
                "mobile":address.mobile,
                "tel":address.tel,
                "email":address.email,
                "province_id": address.province_id,
                "city_id": address.city_id,
                "district_id": address.district_id

            }
            address_list.append(address_dict)

        context = {
                    "default_address_id":request.user.default_address_id,
                    "addresses": address_list
                   }
        return render(request, "user_center_site.html", context)


class AddressCreateView(MyLoginRequiredMiXinView):
    def post(self, request):
        # 1,获取参数
        dict_data = json.loads(request.body.decode())
        title = dict_data.get("title")
        receiver = dict_data.get("receiver")
        province_id = dict_data.get("province_id")
        city_id = dict_data.get("city_id")
        district_id = dict_data.get("district_id")
        place = dict_data.get("place")
        mobile = dict_data.get("mobile")
        tel = dict_data.get("tel")
        email = dict_data.get("email")

        # 2,校验参数
        if not all([title, receiver, province_id, city_id, district_id, place, mobile, tel, email]):
            return HttpResponseForbidden("参数不全")

        # 3,数据入库
        dict_data["user"] = request.user
        address = Address.objects.create(**dict_data)
        # print(dict_data)

        # 4,返回响应
        address_dict = {
            "id": address.id,
            "title": address.title,
            "receiver": address.receiver,
            "province": address.province.name,
            "city": address.city.name,
            "district": address.district.name,
            "place": address.place,
            "mobile": address.mobile,
            "tel": address.tel,
            "email": address.email,
            "province_id": address.province_id,
            "city_id": address.city_id,
            "district_id": address.district_id,
        }
        return JsonResponse({"code": RET.OK, "address": address_dict})


# 修改地址
class AddressUpdateView(MyLoginRequiredMiXinView):

    def put(self, request, address_id):
        json_data = json.loads(request.body.decode())

        title = json_data.get("title")
        receiver = json_data.get("receiver")
        province_id = json_data.get("province_id")
        city_id = json_data.get("city_id")
        district_id = json_data.get("district_id")
        place = json_data.get("place")
        mobile = json_data.get("mobile")
        tel = json_data.get("tel")
        email = json_data.get("email")

        Address.objects.filter(id=address_id).update(
            title=title,
            receiver=receiver,
            province_id=province_id,
            city_id=city_id,
            district_id=district_id,
            place=place,
            mobile=mobile,
            tel=tel,
            email=email
        )

        add_dict = {"title": title, "receiver": receiver,
                    "province_id": province_id,
                    "city_id" :city_id,
                    "district_id": district_id,
                    "place": place,
                    "mobile": mobile,
                    "tel": tel,
                    "email": email}

        data = {"code":RET.OK,"address":add_dict}
        return JsonResponse(data)

    # 删除地址
    def delete(self, request, address_id):
        Address.objects.filter(id=address_id).update(is_deleted=True)
        data = {"code":RET.OK}
        return JsonResponse(data)


# 修改默认地址
class AddressDefaultView(MyLoginRequiredMiXinView):
    def put(self, request, address_id):
        # 获取传过来的address_id
        # print(address_id)
        request.user.default_address_id = address_id
        request.user.save()

        data = {"code":RET.OK}
        return JsonResponse(data)


# 修改title
class AddressTitleView(MyLoginRequiredMiXinView):
    def put(self, request, address_id):

        # 获取参数
        json_data = json.loads(request.body.decode())
        # 获取jsondata中的input_title值
        new_title = json_data.get("title")

        # 为空校验
        if not new_title:
            return HttpResponseForbidden("数据填写不全...")

        # 数据入库
        ret = Address.objects.filter(id=address_id).update(title=new_title)
        if ret == 0:
            return HttpResponseForbidden("标题更新失败...")

        # 返回响应
        data = {
            "code":RET.OK,
            "errmsg":"修改成功"
        }
        return JsonResponse(data)


# 修改密码
class PasswordChangeView(MyLoginRequiredMiXinView):
    def get(self, request):
        return render(request, "user_center_pass.html")

    def post(self, request):

        # 获取参数
        old_pwd = request.POST.get("old_pwd")
        new_pwd = request.POST.get("new_pwd")
        new_cpwd = request.POST.get("new_cpwd")

        # 校验参数
        if not all([old_pwd, new_pwd, new_cpwd]):
            return HttpResponseForbidden("参数不全...")

        if not re.match(r"^[0-9A-Za-z]{8,20}$", old_pwd):
            return HttpResponseForbidden("旧密码格式不正确...")

        if not request.user.check_password(old_pwd):
            return HttpResponseForbidden("旧密码输入错误...")

        if not re.match(r"^[0-9A-Za-z]{8,20}$", new_pwd):
            return HttpResponseForbidden("新密码输入格式不正确...")

        if new_pwd != new_cpwd:
            return HttpResponseForbidden("两次密码输入不一致...")

        # 数据入库
        request.user.set_password(new_pwd)
        request.user.save()

        # 返回响应
        logout(request)
        response = redirect("/login/")
        response.delete_cookie("username")
        return response


# 保存用户浏览记录
class UserBrowserHistoryView(MyLoginRequiredMiXinView):
    def post(self, request):

        # 获取参数
        json_data = json.loads(request.body.decode())
        sku_id = json_data.get("sku_id")
        user = request.user

        # 校验参数

        if not sku_id:
            return HttpResponseForbidden("参数不全...")

        try:
            sku = SKU.objects.get(id=sku_id)

        except Exception as e:
            return HttpResponseForbidden("查无此条记录...")

        # 数据入库
        redis_conn = get_redis_connection("history")

        pipeline = redis_conn.pipeline()

        # 去重
        pipeline.lrem("history_lst_%s" % user.id, sku_id, 0)

        # 存储数据
        pipeline.lpush("history_lst_%s" % user.id, sku_id)

        # 裁剪数据
        pipeline.ltrim("history_lst_%s" % user.id, 0, 4)

        pipeline.execute()

        # 返回响应
        return JsonResponse({"code": RET.OK, "errmsg": "ok"})

    def get(self, request):
        # 从redis里面查出数据
        redis_conn = get_redis_connection("history")

        user = request.user

        history_lst = redis_conn.lrange("history_lst_%s" % user.id, 0, -1)

        skus_lst = list()
        for sku_id in history_lst:

            sku = SKU.objects.get(id=sku_id)
            sku_dict = {
                "id": sku.id,
                "name": sku.name,
                "price": sku.price,
                "default_image_url": sku.default_image_url.url,
            }
            skus_lst.append(sku_dict)

        return JsonResponse({"skus":skus_lst})


class FindPasswordView(View):
    def get(self, request):
        return render(request, "find_password.html")


class CodePhoneCheckerView(View):
    def get(self, request, username):
        # 获取参数
        image_code_id = request.GET.get("image_code_id")
        code = request.GET.get("text")

        # 校验参数
        # 检查用户名是否存在
        if not all([username, image_code_id, code]):
            return HttpResponseForbidden("参数不全")

        try:
            user = User.objects.get(username=username)
            mobile = user.mobile

        except Exception as e:
            try:
                user = User.objects.get(mobile=username)
                mobile = username

            except Exception as e:
                return JsonResponse({"status": 401})

        # 检查验证码是否有误
        redis_conn = get_redis_connection("code")

        image_code_id = "image_code_" + image_code_id

        redis_code = redis_conn.get(image_code_id).decode()

        if not code.upper() == redis_code.upper():
            return JsonResponse({"status": RET.DBERR})

        # 确认都通过后返回正确的结果
        return JsonResponse({"mobile": mobile, "user_id": user.id})


class SmsCheckerView(View):
    def get(self, request, username):

        # 获取数据
        sms_code = request.GET.get("sms_code")

        if not all([username, sms_code]):
            return HttpResponseForbidden("参数不全...")

        # 校验参数
        redis_conn = get_redis_connection("code")

        try:
            user = User.objects.get(username=username)

        except Exception as e:
            return HttpResponseForbidden("用户不存在...")

        redis_sms = redis_conn.get("sms_code_%s" % user.mobile).decode()

        if not redis_sms:
            return HttpResponseForbidden("验证码已经过期")

        if not redis_sms == sms_code:
            response = JsonResponse({})
            response.status_code = 400
            return response

        access_token = "%08d" % random.randint(0, 99999999)

        redis_conn.setex("token_%s" % user.id, 300, access_token)

        return JsonResponse({"user_id": user.id, "access_token": access_token})


class ChangePasswordView(View):
    def post(self, request, user_id):

        # 获取参数
        json_data = json.loads(request.body.decode())

        password = json_data.get("password")
        password2 = json_data.get("password2")
        access_token = json_data.get("access_token")

        # 检验参数
        if not all([user_id, password, password2, access_token]):
            response = JsonResponse({"message":"failed"})
            response.status_code = 400
            return response

        redis_conn = get_redis_connection("code")

        try:
            redis_token = redis_conn.get("token_%s" % user_id).decode()

        except Exception as e:
            response = JsonResponse({"message":"failed"})
            response.status_code = 401
            return response

        if not access_token == redis_token:
            response = JsonResponse({"message":"failed"})
            response.status_code = 401
            return response

        elif not password == password2:
            response = JsonResponse({"message":"failed"})
            response.status_code = 404
            return response

        else:
            user = User.objects.get(id=user_id)

            user.set_password(password)
            user.save()

            response = JsonResponse({"message":"succeed"})
            response.status_code = 200

            return response
